/**
 * Project Name:sjgl
 * Date:2018年12月16日
 * Copyright (c) 2018, jingma All Rights Reserved.
 */

package cn.benma666.sjsj.ljq.qxgl;

import cn.benma666.constants.UtilConst;
import cn.benma666.dict.Cllx;
import cn.benma666.dict.LjqType;
import cn.benma666.dict.Xzms;
import cn.benma666.domain.SysQxYhxx;
import cn.benma666.domain.SysSjglFile;
import cn.benma666.exception.NotFindUserException;
import cn.benma666.iframe.*;
import cn.benma666.myutils.DateUtil;
import cn.benma666.myutils.HttpUtil;
import cn.benma666.json.JsonUtil;
import cn.benma666.myutils.StringUtil;
import cn.benma666.sjsj.web.LjqInterface;
import cn.benma666.sjsj.web.LjqManager;
import cn.benma666.sjsj.web.UserManager;
import cn.benma666.sjzt.MyLambdaQuery;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.captcha.ICaptcha;
import com.alibaba.fastjson.JSONObject;
import org.beetl.sql.core.SqlId;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;

/**
 * 用户登录拦截器 <br/>
 * date: 2018年12月16日 <br/>
 *
 * @author jingma
 */
@Component("SYS_QX_YHXX_MRDL")
@Scope("prototype")
@ConditionalOnProperty(value = "benma666.login.default-login")
public class YhdlLjq extends BasicObject implements LjqInterface {

    public static final String BASIC = "basic";
    /**
     * 验证码缓存
     */
    private static final TimedCache<String, ICaptcha> yamCache = new TimedCache<>(1000 * 60 * 5);

    public Result save(MyParams myParams) {
        myParams.sys().setLjqType(LjqType.dzmrlqj);
        Result r = LjqManager.save(myParams);
        DictManager.clearDict("SYS_QX_YHXX");
        return r;
    }

    /**
     * * 生成验证码
     * @param myParams 参数
     * @return 验证码文件
     */
    public Result scyzm(MyParams myParams){
        final ICaptcha circleCaptcha = CaptchaUtil.createLineCaptcha(200, 50);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        circleCaptcha.write(out);
        //按会话缓存验证码
        yamCache.put(myParams.sys().getToken(),circleCaptcha);
        SysSjglFile file = SysSjglFile.builder().bytes(out.toByteArray())
                .xzms(Xzms.AWJLXXZ.getCode()).wjm("验证码.png").build();
        Result r = success("生成验证码成功", file);
        r.setDateType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        return r;
    }
    /**
     * 用户登陆
     * @return 处理结果
     */
    public Result yhdl(MyParams myParams) {
        SysQxYhxx yobj = myParams.yobj(SysQxYhxx.class);
        //失败次数
        SysQxYhxx user = myParams.user();
        int dlsbcs = user.getDlsbcs();
        //以会话为依据进行控制，还需要控制同一个ip的会话数，避免密码被爆破
        if(dlsbcs>=Conf.getUtilConfig().getLogin().getDlsbcs()){
            //限制时长为会话时长，关闭浏览器重新进入开启新会话其实是可以的，当然系统已经基于ip进行了会话数量限制
            return failed("你登录失败次数过多，请稍后再试");
        }
        //用户账户密码登陆
        if (DateUtil.getGabDate().compareTo(Conf.getVal("sys.yxq")) > 0
                && !UtilConst.SYS.equals(yobj.getYhdm())) {
            return failed("系统版本过旧，请升级后使用");
        }
        if(dlsbcs>0&&Conf.getUtilConfig().getLogin().getYzmEnabled()){
            //登录失败过则必须输入验证码
            if(isBlank(yobj.getYzm())){
                return dlsb(failed("请输入验证码"),myParams);
            }
            final ICaptcha iCaptcha = yamCache.get(myParams.sys().getToken());
            if(iCaptcha==null){
                return dlsb(failed("验证码无效，请刷新验证码"),myParams);
            }
            yamCache.remove(myParams.sys().getToken());
            if(!iCaptcha.verify(yobj.getYzm())){
                return dlsb(failed("验证码错误"),myParams);
            }
        }
        if (StringUtil.isBlank(yobj.getYhmm()) || StringUtil.isBlank(yobj.getYhdm())) {
            return dlsb(failed("用户名或密码为空"),myParams);
        }
        if(user.getYhdm().equals(yobj.getYhdm())){
            return xtjcxx(myParams, user,false);
        }
        JSONObject jsonObj = db().findFirst(SqlId.of("sjsj", "findUser"), myParams);
        if (jsonObj == null) {
            log.info("没有找到该用户:{}",yobj.getYhdm());
            return dlsb(failed("用户名或密码不正确" , yobj.getYhdm()),myParams);
        }
        SysQxYhxx yhxx = jsonObj.toJavaObject(SysQxYhxx.class);
        String yhmm;
        // 获取用户信息基础参数对象
        MyParams yhxxParams = LjqManager.jcxxByDxdm("SYS_QX_YHXX");
        //将用户输入的密码加密
        yhmm = StringUtil.desEnByField(yobj.getYhmm(),yhxxParams.fields().get("yhmm"));
        if (!yhxx.getYhmm().equals(yhmm)) {
            log.info("密码不正确:{}",yobj.getYhdm());
            return dlsb(failed("用户名或密码不正确"),myParams);
        }
        if (StringUtil.isNotBlank(yhxx.getXzip())
                && !user.getClientIp().matches(yhxx.getXzip())) {
            return dlsb(failed("你未不在授权的ip范围内登录"),myParams);
        }
        user = UserManager.findUser(myParams,false);
        if(StringUtil.isNotBlank(yobj.getProjectCode())){
            //传了项目代码，进行微信绑定操作
            //微信登陆
            JSONObject r = HttpUtil.doJosnByFrom(Conf.getVal("wx.api-base-url") + "/sns/jscode2session",
                    Conf.getVal("wx.api-login-params." + yobj.getProjectCode()) + myParams.sys().getToken());
            if (r.getIntValue("errcode") != 0) {
                return failed("微信接口异常："+r.getString("errmsg"));
            }
            log.debug("从微信获取的用户信息："+r.toJSONString());
            //取消该微信用户之前绑定的记录
            MyLambdaQuery<SysQxYhxx> sysQxYhxxMyLambdaQuery = LjqManager.getDb().lambdaQuery(SysQxYhxx.class);
            sysQxYhxxMyLambdaQuery.andEq(SysQxYhxx::getWxyhid,r.getString("openid"));
            sysQxYhxxMyLambdaQuery.updateSelectiveGeneral(SysQxYhxx.builder()
                            .wxyhid("").build());
            //设置新的绑定关系
            sysQxYhxxMyLambdaQuery.andEq(SysQxYhxx::getId,user.getId())
                    .updateSelective(SysQxYhxx.builder()
                            .wxyhid(r.getString("openid"))
                            .wxyhxx(r.toJSONString()).build());
        }
        return xtjcxx(myParams, user);
    }
    public Result dlsb(Result r,MyParams myParams){
        SysQxYhxx user = myParams.getObject(KEY_USER, SysQxYhxx.class);
        user.setDlsbcs(user.getDlsbcs()+1);
        return r;
    }
    /**
     * 转发用户信息，用于第三方系统自动登录
     */
    public Result zfyhxx(MyParams myParams){
        String url = UserManager.doDesEncryptUrl(myParams.getString("$.yobj.url"),
                myParams.getString("$.yobj.projectCode"),
                myParams.getString("$.user.sfzh"));
        Result r = success("成功", url);
        r.setCode(HttpStatus.FOUND.value());
        return r;
    }
    /**
     * 微信登陆
     * @return 处理结果
     */
    public Result wxdl(MyParams myParams) {
        SysQxYhxx oldUser = myParams.user();
        SysQxYhxx yobj = myParams.yobj(SysQxYhxx.class);
        SysQxYhxx user;
        //微信登陆
        JSONObject r = HttpUtil.doJosnByFrom(Conf.getVal("wx.api-base-url",
                "https://api.weixin.qq.com")
                + "/sns/jscode2session",Conf.getVal("wx.api-login-params."
                + yobj.getProjectCode()) + oldUser.getToken());
        if (r.getIntValue("errcode") != 0) {
            return failed("微信接口异常："+r.getString("errmsg"));
        }
        log.debug("从微信获取的用户信息："+r.toJSONString());
        //微信用户唯一标志
        String wxyhid = r.getString("openid");
        if(wxyhid.equals(oldUser.getWxyhid())){
            return xtjcxx(myParams, oldUser,false);
        }
        yobj.setWxyhid(wxyhid);
        try {
            user = UserManager.findUser(myParams,false);
            user.setWxLogin(r);
            return xtjcxx(myParams, user);
        } catch (NotFindUserException e) {
            //系统中还没有该微信用户
            if(valByDef(yobj.getZdcjZh(),false)){
                //自动创建账号
                yobj.setWxyhxx(r.toJSONString());
                yobj.setYhdm(wxyhid);
                yobj.setYhmm(wxyhid);
                yobj.setId(wxyhid);
                yobj.setYhxm("微信用户");
                yobj.setLxdh("123");
                LjqManager.getDb().lambdaQuery(SysQxYhxx.class)
                        .insertSelective(yobj);
                user = UserManager.findUser(myParams,false);
                return xtjcxx(myParams, user);
            }else{
                //返回临时用户
                oldUser.setWxLogin(r);
                return xtjcxx(myParams, oldUser,false);
            }
        }
    }
    /**
     * 用户退出
     * @return 处理结果
     */
    public Result yhtc(MyParams myParams) {
        SysQxYhxx oldUser = myParams.getObject(KEY_USER,SysQxYhxx.class);
        return UserManager.removeUser(oldUser);
    }

    private Result xtjcxx(MyParams myParams, SysQxYhxx user) {
        return xtjcxx(myParams,user,true);
    }
    /**
     * @param myParams 参数
     * @param user 最新用户信息
     * @return 系统基础信息
     */
    private Result xtjcxx(MyParams myParams, SysQxYhxx user,boolean adduser) {
        if(adduser){
            //采用真实ip
            user.setClientIp(myParams.sys().getClientRealIp());
            myParams.put(KEY_USER, user);
            UserManager.addUser(myParams.sys().getToken(), user);
        }
        String model = valByDef(myParams.getString("$.yobj.model"), BASIC);
        if(BASIC.equals(model)){
            JSONObject data = new JSONObject();
            JsonUtil.copy(data, myParams, $_SYS_TOKEN);
            return success("登陆成功",data);
        }else {
            return LjqManager.data(myParams, Cllx.xtjcxx.name());
        }
    }
}
